#include <iostream>
#include <typeinfo>

// 全局的lambda不能捕捉对象
auto fun = [] {};
int x = 1;
int y = 2;
// auto fun1 = [x, y]{};

int main()
{
    auto add1 = [](int a, int b) -> int
    { return a + b; };

    // 1、推导
    auto add2 = add1;
    decltype(add1) add3 = add1;

    // 2、返回值可以省略，明显返回值可以推导
    auto add4 = [](int a, int b)
    { return a + b; };

    // 3、参数列表可省略（没有参数）
    auto fun1 = []()
    { std::cout << "hello!" << std::endl; };

    // 4、参数列表可省略（没有参数）包括圆括号
    auto fun2 = []
    { std::cout << "hello!" << std::endl; };

    // 5、要像函数一样去调用
    fun1();
    fun2();

    // 6、函数体不可以省略、捕捉列表不可以省略
    // 7、最简单的lambda表达式
    [] {};

    std::cout << add3(1, 2) << std::endl;

    // 8、捕捉列表作用
    int a = 1;
    int b = 2;
    auto swap1 = [](int &x, int &y)
    {
        int z = x;
        x = y;
        y = z;
    };
    swap1(a, b);

    // 传值，mutable可以取消x，y的常量性
    // 但是传值不能交换
    auto swap2 = [a, b]() mutable
    {
        int z = a;
        a = b;
        b = a;
    };

    // 不需要参数，直接捕捉
    swap2();

    // 引用捕捉
    auto swap3 = [&a, &b]() mutable
    {
        int z = a;
        a = b;
        b = a;
    };
    swap3();

    // 捕捉方式 =(传值捕捉所有)、a(传值)、b(传值)
    // 捕捉方式 &(传引用捕捉所有)、&a(传引用)、&b(传引用)
    // 不可以重复捕捉
    // auto swap4 = [&, &a, &b]() mutable
    // {
    //     int z = a;
    //     a = b;
    //     b = a;
    // };

    // 9、lambda之间不能赋值(即使类型一样)
    // add3 = add1;

    // 10、lambda的类型推导和lambda的本质
    // std::cout << decltype(swap3) << std::endl;
    std::cout << typeid(swap3).name() << std::endl;
    
    // lambda的本质是一个仿函数,可以通过汇编去查看
    // lambda底层会生成一个lambda_uuid的仿函数

    return 0;
}